package com.bfly.mall.product.service.impl;

import com.bfly.core.base.service.BaseServiceImpl;
import com.bfly.core.context.IpThreadLocal;
import com.bfly.core.enums.SysError;
import com.bfly.core.exception.ServiceResponseException;
import com.bfly.mall.product.dao.FreightTemplateMapper;
import com.bfly.mall.product.dto.FreightFreeConditionsFormDTO;
import com.bfly.mall.product.dto.FreightTemplateFormDTO;
import com.bfly.mall.product.dto.FreightTemplatePricingFormDTO;
import com.bfly.mall.product.entity.*;
import com.bfly.mall.product.enums.PricingMethodEnum;
import com.bfly.mall.product.enums.ShippingMethodEnum;
import com.bfly.mall.product.service.IFreightFreeConditionsService;
import com.bfly.mall.product.service.IFreightTemplatePricingService;
import com.bfly.mall.product.service.IFreightTemplateService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 长沙商脉科技有限公司
 * @date 2020/9/23 16:20
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
public class FreightTemplateServiceImpl extends BaseServiceImpl<FreightTemplate, Integer> implements IFreightTemplateService {

    @Autowired
    private IFreightTemplatePricingService pricingService;
    @Autowired
    private IFreightFreeConditionsService conditionsService;
    @Autowired
    private FreightTemplateMapper freightTemplateMapper;

    /**
     * 校验运送方式
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/11 11:07
     */
    private void checkShipping(FreightTemplateFormDTO formDTO) {
        if (CollectionUtils.isEmpty(formDTO.getPricings())) {
            throw new ServiceResponseException(SysError.MISSING_PARAM, "运送方式不能为空!");
        }

        PricingMethodEnum methodEnum = PricingMethodEnum.getPricingMethod(formDTO.getPricingMethod());
        // 标识判断快递类型的运送方式是否存在默认的全国计费信息 每种运送方式必须有一个默认的运价信息
        boolean isExistDefault = false;

        List<FreightTemplatePricingFormDTO> pricings = formDTO.getPricings();
        for (FreightTemplatePricingFormDTO pricing : pricings) {
            ShippingMethodEnum sme = ShippingMethodEnum.getShippingMethod(pricing.getShippingMethod());
            if (sme == null) {
                throw new ServiceResponseException(SysError.PARAM_ERROR, "运送方式参数错误!");
            }
            if (sme == ShippingMethodEnum.EXPRESS) {
                // 自提不需要校验
                checkNum(methodEnum, pricing.getFirstPiece(), pricing.getFirstWeight(), pricing.getFirstVolume(), pricing.getFirstPrice());
                checkNum(methodEnum, pricing.getNextPiece(), pricing.getNextWeight(), pricing.getNextVolume(), pricing.getNextPrice());
                if (pricing.getFirstPrice().compareTo(pricing.getNextPrice()) < 0) {
                    throw new ServiceResponseException(SysError.MISSING_PARAM, "首费必须大于续费!");
                }
                if (pricing.isDefaults()) {
                    // 默认全国配送运费不需要判断地区
                    isExistDefault = true;
                    pricing.setCityNames("");
                    pricing.setCitys("");
                    continue;
                }
                // 运价方式为快递类型的 需判断需判断是否选择地区
                if (StringUtils.isBlank(pricing.getCitys())) {
                    throw new ServiceResponseException(SysError.MISSING_PARAM, "配送的地区不能为空!");
                }
            } else if (sme == ShippingMethodEnum.SELF_MENTION) {
                // 自提类型不需要判断默认运费
                isExistDefault = true;
                pricing.setCityNames("");
                pricing.setCitys("");
            }
        }
        if (!isExistDefault) {
            throw new ServiceResponseException(SysError.MISSING_PARAM, "默认运费不能为空!");
        }

        ShippingMethodEnum[] methods = ShippingMethodEnum.values();
        for (ShippingMethodEnum method : methods) {
            List<FreightTemplatePricingFormDTO> collect = pricings.stream().filter(condition -> condition.getShippingMethod() == method.getId()).collect(Collectors.toList());
            if (collect.size() < 2) {
                // 至少两组数据比较
                continue;
            }
            Set<String> citySet = new HashSet<>();
            int size = 0;
            for (FreightTemplatePricingFormDTO dto : collect) {
                String citys[] = dto.getCitys().split(",");
                size = size + citys.length;
                for (String city : citys) {
                    citySet.add(city);
                }
            }
            if (size > citySet.size()) {
                throw new ServiceResponseException(SysError.DATA_REPEAT, "同一种运送方式下不能有相同的目的地!");
            }
        }
    }

    /**
     * 校验包邮条件
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/11 11:10
     */
    private void checkCondition(FreightTemplateFormDTO formDTO) {
        if (CollectionUtils.isEmpty(formDTO.getConditions())) {
            throw new ServiceResponseException(SysError.MISSING_PARAM, "包邮条件不能为空!");
        }
        List<FreightFreeConditionsFormDTO> conditions = formDTO.getConditions();
        conditions.forEach(condition -> {
            PricingMethodEnum method = PricingMethodEnum.getPricingMethod(condition.getPricingMethod());
            if (method == null) {
                throw new ServiceResponseException(SysError.PARAM_ERROR, "包邮方式参数错误!");
            }
            ShippingMethodEnum sme = ShippingMethodEnum.getShippingMethod(condition.getShippingMethod());
            if (sme == null) {
                throw new ServiceResponseException(SysError.PARAM_ERROR, "包邮条件运送方式参数错误!");
            }
            checkNum(method, condition.getPieces(), condition.getWeights(), condition.getVolumes(), condition.getPrices());
        });
        ShippingMethodEnum[] methods = ShippingMethodEnum.values();
        for (ShippingMethodEnum method : methods) {
            List<FreightFreeConditionsFormDTO> collect = conditions.stream().filter(condition -> condition.getShippingMethod() == method.getId()).collect(Collectors.toList());
            if (collect.size() < 2) {
                // 至少两组数据比较
                continue;
            }
            Set<String> citySet = new HashSet<>();
            int size = 0;
            for (FreightFreeConditionsFormDTO dto : collect) {
                String citys[] = dto.getCitys().split(",");
                size = size + citys.length;
                for (String city : citys) {
                    citySet.add(city);
                }
            }
            if (size > citySet.size()) {
                throw new ServiceResponseException(SysError.DATA_REPEAT, "指定条件包邮不能选择相同的地址和运送方式!");
            }
        }
    }

    /**
     * 校验运费/件数/重量/体积
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/11 10:54
     */
    private void checkNum(PricingMethodEnum method, int piece, BigDecimal weight, BigDecimal volume, BigDecimal price) {
        String message = null;
        switch (method) {
            case WEIGHT:
                if (weight.compareTo(FreightTemplatePricing.MIN_WEIGHT) < 0 || weight.compareTo(FreightTemplatePricing.MAX_WEIGHT) > 0) {
                    message = String.format("重量必须需在 %s至%s的数字!", FreightTemplatePricing.MIN_WEIGHT.floatValue(), FreightTemplatePricing.MAX_WEIGHT.floatValue());
                }
                break;
            case VOLUME:
                if (volume.compareTo(FreightTemplatePricing.MIN_VOLUME) < 0 || volume.compareTo(FreightTemplatePricing.MAX_WEIGHT) > 0) {
                    message = String.format("体积必须需在 %s至%s的数字!", FreightTemplatePricing.MIN_VOLUME.floatValue(), FreightTemplatePricing.MAX_VOLUME.floatValue());
                }
                break;
            case PIECE:
                if (piece < FreightTemplatePricing.MIN_PIECE || piece > FreightTemplatePricing.MAX_PIECE) {
                    message = String.format("件数必须需在 %s至%s的数字!", FreightTemplatePricing.MIN_PIECE, FreightTemplatePricing.MAX_PIECE);
                }
                break;
            case MONEY:
                if (price.compareTo(FreightTemplatePricing.MIN_PRICE) < 0 || price.compareTo(FreightTemplatePricing.MAX_PRICE) > 0) {
                    message = String.format("金额必须需在 %s至%s的数字!", FreightTemplatePricing.MIN_PRICE.floatValue(), FreightTemplatePricing.MAX_PRICE.floatValue());
                }
                break;
            case PIECE_MONEY:
                if (piece < FreightTemplatePricing.MIN_PIECE || piece > FreightTemplatePricing.MAX_PIECE) {
                    message = String.format("件数必须需在 %s至%s的数字!", FreightTemplatePricing.MIN_PIECE, FreightTemplatePricing.MAX_PIECE);
                }
                if (price.compareTo(FreightTemplatePricing.MIN_PRICE) < 0 || price.compareTo(FreightTemplatePricing.MAX_PRICE) > 0) {
                    message = String.format("金额必须需在 %s至%s的数字!", FreightTemplatePricing.MIN_PRICE.floatValue(), FreightTemplatePricing.MAX_PRICE.floatValue());
                }
                break;
        }
        if (message != null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, message);
        }
    }

    /**
     * 校验运费模板
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/10 22:10
     */
    private void checkFreight(FreightTemplateFormDTO formDTO) {
        PricingMethodEnum methodEnum = PricingMethodEnum.getPricingMethod(formDTO.getPricingMethod());
        if (methodEnum == null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, "计价方式参数错误!");
        }
        if (formDTO.isFreeShipping()) {
            formDTO.setPricings(new ArrayList<>());
            // 免运费情况将包邮条件设置false
            formDTO.setFreeConditions(false);
            formDTO.setConditions(new ArrayList<>());
        } else {
            // 自定义运费数据校验
            checkShipping(formDTO);

            // 指定条件包邮数据校验
            if (formDTO.isFreeConditions()) {
                checkCondition(formDTO);
            } else {
                formDTO.setConditions(new ArrayList<>());
            }
        }
    }

    /**
     * 运送方式
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/10 22:36
     */
    private List<FreightTemplatePricing> getPricings(int templateId, FreightTemplateFormDTO formDTO) {
        List<FreightTemplatePricingFormDTO> pricingFormDTOS = formDTO.getPricings();
        List<FreightTemplatePricing> pricings = new ArrayList<>();
        if (pricingFormDTOS != null) {
            pricingFormDTOS.forEach(dto -> {
                FreightTemplatePricing pricing = new FreightTemplatePricing();
                BeanUtils.copyProperties(dto, pricing);
                pricing.setTemplateId(templateId);
                pricings.add(pricing);
            });
        }
        return pricings;
    }

    /**
     * 包邮条件
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/10 22:36
     */
    private List<FreightFreeConditions> getConditions(int templateId, FreightTemplateFormDTO formDTO) {
        List<FreightFreeConditionsFormDTO> conditionsFormDTOS = formDTO.getConditions();
        List<FreightFreeConditions> conditions = new ArrayList<>();
        if (conditionsFormDTOS != null) {
            conditionsFormDTOS.forEach(dto -> {
                FreightFreeConditions condition = new FreightFreeConditions();
                BeanUtils.copyProperties(dto, condition);
                condition.setTemplateId(templateId);
                conditions.add(condition);
            });
        }
        return conditions;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(FreightTemplateFormDTO formDTO) {
        checkFreight(formDTO);
        FreightTemplate template = new FreightTemplate();

        BeanUtils.copyProperties(formDTO, template);

        template.setDeleted(false);
        template.setCreateDate(new Date());
        template.setCreateIp(IpThreadLocal.get());
        super.save(template);

        List<FreightTemplatePricing> pricings = getPricings(template.getId(), formDTO);
        List<FreightFreeConditions> conditions = getConditions(template.getId(), formDTO);

        pricings.forEach(pricing -> {
            pricingService.save(pricing);
        });

        conditions.forEach(condition -> {
            conditionsService.save(condition);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(FreightTemplateFormDTO formDTO) {
        checkFreight(formDTO);

        FreightTemplate template = super.get(formDTO.getId());
        if (template == null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, "不存在的运费模板信息!");
        }
        template.setName(formDTO.getName());
        template.setFreeConditions(formDTO.isFreeConditions());
        template.setFreeShipping(formDTO.isFreeShipping());
        List<FreightTemplatePricing> pricings = getPricings(template.getId(), formDTO);
        List<FreightFreeConditions> conditions = getConditions(template.getId(), formDTO);

        // 先清空原有的计价方式和包邮条件然后新增
        pricingService.clearPricing(formDTO.getId());
        conditionsService.clearCondition(formDTO.getId());

        pricings.forEach(pricing -> {
            pricingService.save(pricing);
        });

        conditions.forEach(condition -> {
            conditionsService.save(condition);
        });

        template.setUpdateDate(new Date());
        super.edit(template);
    }

    @Override
    public FreightTemplate getFreight(int productId) {
        return freightTemplateMapper.getFreight(productId);
    }
}
